package com.pocket.demo.core.security;

import com.pocket.demo.base.consts.RequestConst;
import com.pocket.demo.business.service.PocketUserDetailsService;
import com.pocket.demo.core.context.TokenContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.DeferredSecurityContext;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.web.context.HttpRequestResponseHolder;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.util.StringUtils;

import java.util.UUID;

/**
 * 自定义 SecurityContext 存储器 【demo-SpringSecurity-3.5】
 * @author zhaozhile
 */
public class RedisSecurityContextRepository implements SecurityContextRepository {

    private static final Logger LOGGER = LoggerFactory.getLogger(RedisSecurityContextRepository.class);

    private final SecurityContextHolderStrategy contextHolderStrategy = SecurityContextHolder.getContextHolderStrategy();

    private PocketUserDetailsService userDetailsService;

    public RedisSecurityContextRepository(PocketUserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    // 获得当前安全上下文
    @Override
    public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
        LOGGER.debug("request【{}】loadContext", requestResponseHolder.getRequest().getRequestURI());
        SecurityContext emptyContext = this.contextHolderStrategy.createEmptyContext();
        String token = TokenContext.getToken();
        if (!StringUtils.hasText(token)){
            return emptyContext;
        }
        PocketUser pocketUser = userDetailsService.loadUserBySessionId(token);
        if (pocketUser == null){
            return emptyContext;
        }
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(pocketUser,null,null);
        emptyContext.setAuthentication(authenticationToken);
        return emptyContext;
    }

    @Override
    public DeferredSecurityContext loadDeferredContext(HttpServletRequest request) {
        LOGGER.debug("request【{}】loadDeferredContext", request.getRequestURI());
        return SecurityContextRepository.super.loadDeferredContext(request);
    }

    // 保存安全上下文
    @Override
    public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) {
        LOGGER.debug("save request【{}】SecurityContext", request.getRequestURI());
        String token = TokenContext.getToken();
        if (!StringUtils.hasText(token)){
            // 【demo-SpringSecurity-4.1】
            token = UUID.randomUUID().toString();
            TokenContext.setToken(token);
        }

        Authentication authentication = context.getAuthentication();
        if (authentication != null){
            PocketUser pocketUser = (PocketUser) context.getAuthentication().getPrincipal();
            userDetailsService.saveUserSession(token, pocketUser);
        }
    }

    // 查看Request是否包含当前用户的安全上下文
    @Override
    public boolean containsContext(HttpServletRequest request) {
        LOGGER.debug("request【{}】containsContext", request.getRequestURI());
        CharSequence authorization = request.getHeader(RequestConst.HEAD_AUTHORIZATION);
        return StringUtils.hasText(authorization);
    }
}
